﻿using System;
using System.Diagnostics;
using ReAnimation.Helpers.Common;
using Tao.OpenGl;
using System.Collections.Generic;
using ReAnimation.Helpers.WinForms;
using Sharp3D.Math.Core;
using GLWrap.MathExt;

namespace GLWrap.SceneObjects
{
    public abstract class SceneObject
    {
        protected IList<GlSceneManager> _sceneManagers;
            //TODO: надо сделать тип int, а то слишком мало объектов
        private static Int32 _objectId = 0;
        internal Int32 ObjectId { get; private set; }

        public virtual Material Material { get; set; }
        public Matrix4F TransformationMatrix { get; set; }

        public event EventHandler OnSelect;
        public event EventHandler<EventArg<GlSceneManager>> WillDraw;
        public event EventHandler<EventArg<GlSceneManager>> WasDrawn;

        public SceneObject()
        {
            _sceneManagers = new List<GlSceneManager>();
            TransformationMatrix = Matrix4F.Identity;
            ObjectId = _objectId++;
        }

        public void Draw(GlSceneManager sceneManager)
        {
            WillDraw.Throw(this,new EventArg<GlSceneManager>(sceneManager));
            {
                Gl.glColor3ub((byte)(ObjectId & 255), (byte)((ObjectId >> 8) & 255), (byte)((ObjectId >> 16) & 255));
                if (Material != null)
                    Material.ApplyMaterial();
                Gl.glPushMatrix();
                {
                    Gl.glMultMatrixf(TransformationMatrix.TranslateToGL());
                    InternalDraw(sceneManager);
                }
                Gl.glPopMatrix();
            }
            WasDrawn.Throw(this,new EventArg<GlSceneManager>(sceneManager));
        }

        internal void AttachToScene(GlSceneManager sceneManager)
        {
            if (!_sceneManagers.Contains(sceneManager))
            {
                _sceneManagers.Add(sceneManager);
                InternalAttachToScene(sceneManager);
            }
        }

        internal void DetachFromScene(GlSceneManager sceneManager)
        {
                _sceneManagers.Remove(sceneManager);
                InternalDetachFromScene(sceneManager);
        }

        protected virtual void InternalAttachToScene(GlSceneManager sceneManager) { }
        protected virtual void InternalDetachFromScene(GlSceneManager sceneManager) { }
        protected virtual void InternalDraw(GlSceneManager sceneManager) { }

        internal void HaveBeenSelected()
        {
            OnSelect.Throw(this,EventArgs.Empty);
        }
    }
}